use std::{collections::HashMap, vec};
use std::sync::Arc;
use rocket::Request;
use rocket::serde::json::Json;
use serde::{Deserialize, Serialize};
use crate::protocol::task::TaskSignature;
use crate::protocol::type_derive::FuseDirection;
use crate::routes::workflow;
use crate::{abstractions::fuse::fuse_symbolic, error::ServerError, protocol::task::{NominalTask, SymbolicTask}};
use crate::workflows::workflow_task::get_all_tasks_bound;
use crate::workflows::workflow::Workflow;
use crate::workflows::manager::WORKFLOW_MANAGER;
use crate::protocol::type_schema::TypeSchema;
use crate::abstractions::task::{TaskAbstraction, TaskId};
use crate::workflows::portable_run::start_workflow_func;
use uuid::Uuid;
use super::portable_run::get_available_port;
use super::workflow::{RunningWorkflow, WorkflowRunningStatus};
use crate::protocol::type_derive::IOFixed;

impl FuseDirection {
    pub fn from_bool(b: bool) -> Self {
        if b {
            Self::Positive
        } else {
            Self::Negative
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct ValidTaskA {
    ibound: Option<NominalTask>,
    obound: Option<NominalTask>,
    ifix: bool,
    ofix: bool,
    force: bool,
}

#[derive(Debug, Serialize)]
pub struct ValidTaskB {
    tasks: Vec<(String, String, String)>,
}

#[post("/workflows/valid_tasks", data = "<req>")]
pub async fn valid_tasks(req: Json<ValidTaskA>) -> Result<Json<ValidTaskB>, ServerError> {
    if let Some(ibound) = &req.ibound {
        SymbolicTask::try_parse_loose(&ibound)?;
    }
    if let Some(obound) = &req.obound {
        SymbolicTask::try_parse_loose(&obound)?;
    }
    let tasks = get_all_tasks_bound(req.ibound.clone(), req.obound.clone(), IOFixed::from_bools(req.ifix, req.ofix), req.force);
    let tasks = tasks.into_iter().map(|(name, task, fused)| (name, task.short_str(), fused.short_str())).collect();
    Ok(Json(ValidTaskB { tasks }))
}

#[derive(Debug, Deserialize)]
pub struct AddWorkFlowA {
    task_names: Vec<String>,
    fuse_params: Vec<(bool, bool)>,
    task_sig: NominalTask,
}

#[derive(Debug, Serialize)]
pub struct AddWorkFlowB {
    success: bool,
    workflow_name: String,
    error: Option<String>,
}

#[post("/workflows/add_workflow", data = "<req>")]
pub async fn add_workflow(req: Json<AddWorkFlowA>) -> Result<Json<AddWorkFlowB>, ServerError> {
    let symbolic = SymbolicTask::try_parse_loose(&req.task_sig)?;
    let workflow_name = symbolic.name;
    let input_type = symbolic.input_type;
    let output_type = symbolic.output_type;
    let mut tasks = vec![];
    let mut manager = WORKFLOW_MANAGER.get().unwrap().lock().unwrap();
    for task_name_full in &req.task_names {
        let mut splits = task_name_full.split('.');
        if let (Some(service_name), Some(task_name), None) = (splits.next(), splits.next(), splits.next()) {
            if service_name == "builtin" {
                if let Some(task) = manager.all_builtin_taskabs.get(task_name_full) {
                    tasks.push(task.clone());
                } else {
                    return Err(ServerError::WorkflowError(format!("builtin任务不存在: {}", task_name_full)));
                }
            } else {
                if let Some(service_id) = manager.task_name_to_id.get(task_name_full) {
                    let task_id: TaskId = (service_id.clone(), task_name.to_string());
                    tasks.push(Arc::new(TaskAbstraction::FromService(task_id)));
                } else {
                    return Err(ServerError::WorkflowError(format!("任务名不存在: {}", task_name_full)));
                }
            }
        } else {
            return Err(ServerError::WorkflowError(format!("任务名格式错误: {}", task_name_full)));
        }
    }
    let mut fuse_params = vec![];
    for fuse_param in &req.fuse_params {
        fuse_params.push((FuseDirection::from_bool(fuse_param.0), fuse_param.1));
    }
    let workflow = Workflow::Static(workflow_name.clone(), input_type, output_type, tasks, fuse_params);
    let workflow = workflow.into_portable()?;
    manager.add_workflow(workflow)?;
    drop(manager);
    Ok(Json(AddWorkFlowB { success: true, workflow_name, error: None }))
}

#[derive(Debug, Deserialize)]
pub struct StartWorkflowA {
    workflow_name: String,
    input_file_content: String,
}

#[derive(Debug, Serialize)]
pub struct StartWorkflowB {
    success: bool,
    port: u16,
    name: String,
    error: Option<String>,
}

#[post("/workflows/start", data = "<req>")]
pub async fn start_workflow(req: Json<StartWorkflowA>) -> Result<Json<StartWorkflowB>, ServerError> {
    let workflow_name = req.workflow_name.clone();
    let input = req.input_file_content.clone();
    let port: u16 = get_available_port();
    let mut manager = WORKFLOW_MANAGER.get().unwrap().lock().unwrap();
    manager.create_portable_running_workflow(workflow_name.clone(), port);
    if let Some(workflow) = manager.get_workflow(&workflow_name) {
        let output = start_workflow_func(workflow, input, port)?;
    } else {
        return Err(ServerError::WorkflowError(format!("工作流不存在: {}", workflow_name)))
    }
    Ok(Json(StartWorkflowB { success: true, port, name: workflow_name, error: None }))
}

#[derive(Debug, Serialize)]
pub struct GetRunningWorkflowsB {
    running_workflows: HashMap<u16, RunningWorkflow>,
}

#[get("/workflows/running")]
pub async fn get_running_workflows() -> Result<Json<GetRunningWorkflowsB>, ServerError> {
    let manager: std::sync::MutexGuard<'_, super::manager::WorkflowManager> = WORKFLOW_MANAGER.get().unwrap().lock().unwrap();
    let running_workflows = manager.get_running_workflows();
    Ok(Json(GetRunningWorkflowsB { running_workflows }))
}

#[get("/workflows/running/<port>/result")]
pub async fn get_running_workflow_result(port: u16) -> Result<String, ServerError> {
    let manager = WORKFLOW_MANAGER.get().unwrap().lock().unwrap();
    if let Some(res) = manager.portable_running_workflows_result.get(&port) {
        match res {
            Ok(data) => Ok(data.to_json_less().to_string()),
            Err(e) => Err(e.clone()),
        }
    } else {
        return Err(ServerError::WorkflowError(format!("portable running workflow result 不存在: {}", port)));
    }
}

#[delete("/workflows/running/<port>")]
pub async fn delete_running_workflow(port: u16) -> Result<Json<DeleteWorkflowB>, ServerError> {
    let mut manager = WORKFLOW_MANAGER.get().unwrap().lock().unwrap();
    if let Some(workflow) = manager.portable_running_workflows.get(&port) {
        if workflow.status.is_not_finished() {
            return Err(ServerError::WorkflowError(format!("portable running workflow 正在运行，无法删除: {}", port)));
        }
        // workflow.terminate()?;
    } else {
        return Err(ServerError::WorkflowError(format!("portable running workflow 不存在: {}", port)));
    }
    manager.delete_running_workflow(port)?;
    Ok(Json(DeleteWorkflowB { success: true, error: None }))
}

#[derive(Debug, Serialize)]
pub struct GetAllWorkflowsB {
    workflow_sigs: Vec<TaskSignature>,
}

#[get("/workflows/all")]
pub async fn get_all_workflows() -> Result<Json<GetAllWorkflowsB>, ServerError> {
    let manager = WORKFLOW_MANAGER.get().unwrap().lock().unwrap();
    let workflow_sigs = manager.get_all_workflow_sigs();
    let workflow_sigs = workflow_sigs.iter().map(|sig| sig.short_sig()).collect();
    Ok(Json(GetAllWorkflowsB { workflow_sigs }))
}

#[derive(Debug, Serialize)]
pub struct WorkflowInfoB {
    id: String,
    name: String,
    description: Option<String>,
    input_type: String,
    output_type: String,
}

#[get("/workflows/get/<workflow_id>")]
pub async fn get_workflow(workflow_id: &str) -> Result<Json<WorkflowInfoB>, ServerError> {
    let manager = WORKFLOW_MANAGER.get().unwrap().lock().unwrap();
    
    if let Some(workflow) = manager.get_workflow(workflow_id) {
        Ok(Json(WorkflowInfoB {
            id: workflow_id.to_string(),
            name: workflow_id.to_string(),
            description: None,
            input_type: workflow.tin().to_string(),
            output_type: workflow.tout().to_string(),
        }))
    } else {
        Err(ServerError::WorkflowError(format!("工作流不存在: {}", workflow_id)))
    }
}

#[derive(Debug, Serialize)]
pub struct DeleteWorkflowB {
    success: bool,
    error: Option<String>,
}

#[delete("/workflows/delete/<workflow_id>")]
pub async fn delete_workflow(workflow_id: &str) -> Result<Json<DeleteWorkflowB>, ServerError> {
    let mut manager = WORKFLOW_MANAGER.get().unwrap().lock().unwrap();
    manager.delete_workflow(workflow_id)?;
    Ok(Json(DeleteWorkflowB { success: true, error: None }))
}